<!DOCTYPE body PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>

<style>
ol li {
	list-style-type: lower-alpha
}

pre {
	line-height: 150%;
	display: inline-block;
	/* border:2px solid Black; */
	background-color: #ddd;
	padding: 10px;
}
</style>

	<h1>Úvod</h1>
	Liboptions je knihovna pro Java 1.6+ na parsování argumentů na
	příkazové řádce. Umožňuje
	<ol>
		<li>definovat, které parametry očekává, jakou mají mít typ
			hodnoty (pokud vůbec)</li>
		<li>pomocí této definice naparsovat vstupní argumenty</li>
		<li>reagovat na zadané parametry a jejich hodnoty</li>
	</ol>

	<p>
		Zadání pro tuto knihovnu najdete zde:
		<tt>
			<a
				href="http://d3s.mff.cuni.cz/teaching/programming_practices/ukol2/">http://d3s.mff.cuni.cz/teaching/programming_practices/ukol2/</a>
		</tt>
	<h1>Jak se builduje</h1>

	<p>
		Knihovna se builduje pomocí nástroje <i>Ant</i>, příkazem
		<tt>ant</tt>
		v rootu projektu (spusti defaultni goal ant pakcage) výsledkem je
		<tt>target/liboptions.jar</tt>
		. Tento jar je závislý pouze na
		<tt>slf4j-api</tt>
		(1.6.4), které najdete ve složce
		<tt>lib/</tt>
		. Tato knihovna slouží pro logování, repsektive pomocí ní můžete
		napojit svůj oblíbený logovací framework viz <a
			href="http://www.slf4j.org">http://www.slf4j.org/</a>
	</p>

	<p>
		Vedle toho můžete spustit testy (ze složky
		<tt>tests/</tt>
		, zavilsé navíc na obsahu
		<tt>test-lib/</tt>
		) pomocí
		<tt>ant test</tt>
		. Výsledek najdete v
		<tt>target/test-reprots</tt>
		.
	</p>

	<p>
		JavaDoc se generuje pomocí
		<tt>ant jdoc</tt>
		do složky
		<tt>target/jdoc</tt>
		.
	</p>

	<h1>Ukázky použití</h1>

	<h3>Úvodní příklad</h3>

	<p>Nejprve se vyvtoří základní objekty spravující všechny volby.</p>

	<pre>
Options options = new Options();
</pre>

	<p>Vytvoření volby typu string, nejprve se vyrobí callback, který
		bude zavolán, když se daná volba nachází mezi předanými argumenty.</p>


	<pre>
OptionCallback&lt;String&gt; wordCallback = new OptionCallbackAdapter&lt;String&gt;() {
    public void handleOptionValue(String parameter) {
        logger.info("word argument has parameter: {}", parameter);
    }
};</pre>

	<p>
		V dalším kroku se vytvoří samotná volba, nastaví se její parametry a
		nakonec se přidá do hlavního objektu
		<tt>options</tt>
		.
	</p>


	<pre>
// vytvori novou volbu --word s retezcovym parametrem
// WORD funguje jako nazev parametru, bude videt v helpu: --word=WORD
// (resp. -w WORD)
StringOption wordOption = new StringOption.Builder("word", "WORD")
        .addAlias("w")              // prida kratkou volbu -s jako synonymum 
        .setDescription("testovaci option typu string")
        .setCallback(wordCallback)
        .setObligatory(true)        // nastavi volbu jako povinnou
        .buildOption();

// prida volbu do Options
options.addOptionDefinition(wordOption);
</pre>

	<p>
		Analogicky se postupuje i pro volby ostatních typů. Úplný výpis lze
		najít v
		<tt>tests/cz/mff/cuni/dpp/liboptions/SimpleTest.java</tt>
		.
	</p>

	<p>
		V připadně boolovské volby (switch) je vhodné implementovat i metodu
		<tt>handleNotPresent</tt>
		z rozhrani
		<tt>OptionCallback</tt>
		.
	</p>

	<pre>
// vytvori callback pro booleovskou volbu (switch)
OptionCallback&lt;Boolean&gt; switchCallback = new OptionCallback&lt;Boolean&gt;() {
    public void handleOptionValue(Boolean parameter) {
        logger.info("switch is on");
    }
    <b> public void handleNotPresent() {
        logger.info("switch is off");
    } </b>
};
</pre>

	<p>V případě řetězce z pevně daného seznamu se volbě navíc předá
		tento seznam.</p>

	<pre>
EnumOption enumOption = new EnumOption.Builder("enum", "WORD-FROM-SET")
    .addAlias("e")
    .setDescription("vyber slov z mnoziny: alpha, beta, gama")
    <b>.addAllowedValues("alpha", "beta", "gama")</b>
    .setCaseSensitive(false)        // vypne rozlisovani velkych malych pismen
    .setCallback(enumCallback)
    .buildOption();
</pre>

	<p>
		Nakonec se zavolá zpracování argumentu a v případě, že se nevyskytnou
		chyby, zavolají se všechny callbacky. Když @see java.lang.String je u
		<tt>callCallbacks</tt>
		parametr
		<tt>true</tt>
		, zavolají se i callbacky nepřítomných argumentů, to se hodí pro
		switche nebo pro nastavení defaultních hodnot.
	</p>

	<pre>
Result result = options.process(args);

if (result.hasErrors()) {
    options.printHelp();
} else {
    result.callCallbacks(true);
}
</pre>

	<p>A takto lze vyvolat vypsání nápovědy, předaný řetězec se objeví
		na úvodní řádce před výpisem jednotlivých voleb.</p>

	<pre>
options.printHelp("./test [options] [argumennts]");
</pre>

	<h3>Program GNU time</h3>


	<p>
		Ukázka, jak by vypadalo použití knihovny pro program GNU Time
		(dostupné v souboru
		<tt>tests/cz/mff/cuni/dpp/liboptions/TimeTest.java</tt>
		) Pro přehlednost jsou vynechány definice callbacků.
	</p>

	<pre>
Options options = new Options();

StringOption formatterOption = new StringOption.Builder("format", "FORMAT")
        .addAlias("f")
        .setDescription(
                "Specify output format, possibly overriding the format specified in the environment variable TIME.")
        .setCallback(formatterCallback)
        .buildOption();

StringOption outputOption = new StringOption.Builder("output", "FILE")
        .addAlias("o")
        .setDescription(
                "Do not send the results to stderr, but overwrite the specified file.")
        .setCallback(outputCallback)
        .buildOption();

SwitchOption portabilityOption = new SwitchOption.Builder("portability").addAlias("p")
        .setCallback(portabilityCallback)
        .setDescription("Use the portable output format.")
        .buildOption();

SwitchOption appendOption = new SwitchOption.Builder("append")
        .addAlias("a")
        .setDescription("(Used together with -o.) Do not overwrite but append.")
        .setCallback(appendCallback)
        .buildOption();

SwitchOption verboseOption = new SwitchOption.Builder("verbose")
        .addAlias("v")
        .setDescription("Give very verbose output about all the program knows about.")
        .setCallback(verboseCallback)
        .buildOption();

SwitchOption helpOption = new SwitchOption.Builder("help")
        .setDescription("Print a usage message on standard output and exit successfully.")
        .setCallback(new HelpCallback(options, "time [options] command [arguments...]"))
        .buildOption();

SwitchOption versionOption = new SwitchOption.Builder("version")
        .addAlias("V")
        .setDescription(
                "Print version information on standard output, then exit successfully.")
        .setCallback(new VersionCallback())
        .buildOption();

options.addOptionDefinition(formatterOption);
options.addOptionDefinition(outputOption);
options.addOptionDefinition(portabilityOption);
options.addOptionDefinition(appendOption);
options.addOptionDefinition(verboseOption);
options.addOptionDefinition(helpOption);
options.addOptionDefinition(versionOption);

Result result = options.process(args);

if (result.hasErrors()) {
    options.printHelp();
} else {
    result.callCallbacks(true);
}
</pre>

	<h3>Velká ukázka použití.</h3>

	<p>
		(dostpná v souboru
		<tt>tests/cz/mff/cuni/dpp/liboptions/UsageTemplateTest.java</tt>
		)
	</p>
	<p>Přístup k použití knihovnz není konzistetní (jednou je použit)
		callback, podruhé test přítomnosti optionu v resultu - ale to je proto
		aby toho ukázka ukázala co nejvíc.</p>


	<pre>
private static final String SWITCH_PLUS = "plus";
private static final String SWITCH_MINUS = "minus";

private static int number;
private static String label = "RESULT:";

/**
 * Pro cisla od 10 do 20 prida nebo ubere jednicku a vypise vysledek
 */
public static void main(String[] args) {
    Options options = new Options();
    // Povinna volba cisla v rozmezi 10-20, pritmomnost vyvola callback
    IntegerOption numberOption = new IntegerOption.Builder("number", "NUMBER-OF-SMTHNG", true)
            .addAlias("n").setLowerBound(10).setUpperBound(20)
            .setCallback(new OptionCallbackAdapter&lt;Integer&gt;() {
                public void handleOptionValue(Integer parameter) {
                    number = parameter;
                }
            }).buildOption();
    // Povinna volba ze dvou prvku, na velikosti nezalezi
    EnumOption chooseOption = new EnumOption.Builder("operation", "OPERATION")
            .setObligatory(true).addAlias("o").addAllowedValues(SWITCH_PLUS, SWITCH_MINUS)
            .setCaseSensitive(false).buildOption();
    // Nepovinna volba se stringovou hodnotou
    StringOption labelOption = new StringOption.Builder("label", "LABEL").addAlias("l")
            .buildOption();
    // Volitelny prepinac pro vzpsani helpu, u builderu neni vyuzit fluid
    // interface
    SwitchOption.Builder helpBuilder = new SwitchOption.Builder("help");
    helpBuilder.addAlias("h");
    helpBuilder
            .setDescription("Je sranda, ze jenom parametr help ma popisek, takze se stejne nic nedozvite");
    SwitchOption helpOption = helpBuilder.buildOption();

    // Vsechny optionz musime "zapojit", pokud by doslo ke konfliktu nazvu
    // nebo aliasu dosatnu vyjimku!
    options.addOptionDefinition(numberOption);
    options.addOptionDefinition(labelOption);
    options.addOptionDefinition(chooseOption);
    options.addOptionDefinition(helpOption);

    // Zpracovani vstupu od uziavtele
    Result result = options.process(args);

    // Pokud uzovatel zapomel neco zadat, nebo chce napovedu
    if (result.hasErrors() || result.isPresent(helpOption)) {
        options.printHelp();

        // reakce na specifikou chybu            
        if (result.getErrors().getOutOfRange().containsKey(numberOption)) {
            //Spatna hodnota je vzdy String
            String badValue = result.getErrors().getOutOfRange().get(numberOption);
            System.out.println("umim pocitat pouze do dvou ne do " + badValue);
        }
    } else {
        // vyvolame callback
        result.callCallbacks(false);

        // Takto se muze pristoupit na hodnoty
        if (result.isPresent(labelOption)) {
            label = result.getValue(labelOption);
        }

        // vime ze nebyl error a tedy chooseOption musi byt pritomen
        String operation = result.getValue(chooseOption);
        if (SWITCH_MINUS.equalsIgnoreCase(operation)) {
            number--;
        } else if (SWITCH_PLUS.equalsIgnoreCase(operation)) {
            number++;
        } else {
            // sem se nikdy kod nedostane
        }

        System.out.println(label + number);

        // Pokud bych potreboval sahat na argumety
        result.getArguments();
    }

}
</pre>

</body>
</html>
